﻿// The code in this file comes from Matt Warren's series of blog posts on how to build a LINQ provider
// http://blogs.msdn.com/mattwar/archive/2007/08/09/linq-building-an-iqueryable-provider-part-i.aspx

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

using log4net;

namespace FreeBase.Linq
{
	/// <summary>
	/// 
	/// </summary>
	public class Query<T> :
		IQueryable<T>, IQueryable,
	IEnumerable<T>, IEnumerable,
	IOrderedQueryable<T>, IOrderedQueryable
	{
		IQueryProvider _provider;
		Expression _expression;
		private readonly ILog logger = LogManager.GetLogger( typeof( ResponseParser ) );
		

		public Query( IQueryProvider provider )
		{
			if ( provider == null )
				throw new ArgumentNullException( "provider" );

			this._provider = provider;
			this._expression = Expression.Constant( this );
		}

		public Query( QueryProvider provider, Expression expression )
		{
			if ( provider == null )
				throw new ArgumentNullException( "provider" );

			if ( expression == null )
				throw new ArgumentNullException( "expression" );

			if ( !typeof( IQueryable<T> ).IsAssignableFrom( expression.Type ) )
				throw new ArgumentOutOfRangeException( "expression" );

			this._provider = provider;
			this._expression = expression;
		}

		Expression IQueryable.Expression
		{
			get { return this._expression; }
		}

		Type IQueryable.ElementType
		{
			get { return typeof( T ); }
		}

		IQueryProvider IQueryable.Provider
		{
			get { return this._provider; }
		}

		public IEnumerator<T> GetEnumerator()
		{
			logger.Debug( "Running Query.GetEnumerator generic method with T a type of " + typeof(T).Name );
			IEnumerable<T> returnedEnumerable = ( ( IEnumerable<T> )this._provider.Execute<IList<T>>( this._expression ) );
#if DEBUG			
			foreach( T retreivedObject in returnedEnumerable )
				logger.Debug( "Retrieved " + retreivedObject.ToString() );
#endif
			return returnedEnumerable.GetEnumerator( );
		}

		IEnumerator IEnumerable.GetEnumerator( )
		{
			logger.Debug( "Running Query.GetEnumerator method" );
			return ( ( IEnumerable )this._provider.Execute<IList<T>>( this._expression ) ).GetEnumerator( );
		}

		public override string ToString( )
		{
			return this._provider.ToString(); //.GetQueryText( this._expression );
		}
	}
}